﻿using System;
using System.ComponentModel;
using System.Data.Linq;
using System.Data.Linq.Mapping;
using Model.Interfaces;
using Model.ModelEventArgs;

namespace Data.MappingClasses
{
    [TableAttribute(Name = "dbo.Student")]
    public partial class Student : AbstractMappingClass, INotifyPropertyChanging, INotifyPropertyChanged
    {
        public event EventHandler<ModelItemEventArgs> AddedGroupEvent;
        public event EventHandler<ModelItemEventArgs> RemovedGroupEvent;

        public event EventHandler<ModelItemEventArgs> AddedPaymentEvent;
        public event EventHandler<ModelItemEventArgs> RemovedPaymentEvent;

        private static PropertyChangingEventArgs emptyChangingEventArgs = new PropertyChangingEventArgs(String.Empty);

        private short _idStudent;

        private Nullable<short> _refFaculty;

        private Nullable<short> _refSchool;

        private Nullable<short> _refAddress;

        private string _familyName;

        private string _studentName;

        private string _fatherName;

        private Nullable<DateTime> _bornDate;

        private string _email;

        private string _homePhone;

        private string _mobilePhone;

        private string _additionalPhone;

        private bool _isPrivilege;

        private EntitySet<Payment> _Payments;

        private EntitySet<StudentGroup> _StudentGroups;

        private EntityRef<Address> _Address;

        private EntityRef<Faculty> _Faculty;

        private EntityRef<School> _School;

        #region Extensibility Method Definitions
        partial void OnLoaded();
        partial void OnValidate(System.Data.Linq.ChangeAction action);
        partial void OnCreated();
        partial void OnidStudentChanging(short value);
        partial void OnidStudentChanged();
        partial void OnrefFacultyChanging(System.Nullable<short> value);
        partial void OnrefFacultyChanged();
        partial void OnrefSchoolChanging(System.Nullable<short> value);
        partial void OnrefSchoolChanged();
        partial void OnrefAddressChanging(System.Nullable<short> value);
        partial void OnrefAddressChanged();
        partial void OnfamilyNameChanging(string value);
        partial void OnfamilyNameChanged();
        partial void OnstudentNameChanging(string value);
        partial void OnstudentNameChanged();
        partial void OnfatherNameChanging(string value);
        partial void OnfatherNameChanged();
        partial void OnbornDateChanging(System.Nullable<System.DateTime> value);
        partial void OnbornDateChanged();
        partial void OnemailChanging(string value);
        partial void OnemailChanged();
        partial void OnhomePhoneChanging(string value);
        partial void OnhomePhoneChanged();
        partial void OnmobilePhoneChanging(string value);
        partial void OnmobilePhoneChanged();
        partial void OnadditionalPhoneChanging(string value);
        partial void OnadditionalPhoneChanged();
        partial void OnisPrivilegeChanging(System.Nullable<bool> value);
        partial void OnisPrivilegeChanged();
        #endregion

        public Student()
        {
            this._Payments = new EntitySet<Payment>(new Action<Payment>(this.AttachPayments), new Action<Payment>(this.DetachPayments));
            this._StudentGroups = new EntitySet<StudentGroup>(new Action<StudentGroup>(this.AttachStudentGroups), new Action<StudentGroup>(this.DetachStudentGroups));
            this._Address = default(EntityRef<Address>);
            this._Faculty = default(EntityRef<Faculty>);
            this._School = default(EntityRef<School>);
            OnCreated();
        }

        [ColumnAttribute(Storage = "_idStudent", AutoSync = AutoSync.OnInsert, DbType = "SmallInt NOT NULL IDENTITY", IsPrimaryKey = true, IsDbGenerated = true)]
        public short idStudent
        {
            get
            {
                return this._idStudent;
            }
            set
            {
                if ((this._idStudent != value))
                {
                    this.OnidStudentChanging(value);
                    this.SendPropertyChanging();
                    this._idStudent = value;
                    this.SendPropertyChanged("idStudent");
                    this.OnidStudentChanged();
                }
            }
        }

        [ColumnAttribute(Storage = "_refFaculty", DbType = "SmallInt")]
        public Nullable<short> refFaculty
        {
            get
            {
                return this._refFaculty;
            }
            set
            {
                if ((this._refFaculty != value))
                {
                    if (this._Faculty.HasLoadedOrAssignedValue)
                    {
                        throw new System.Data.Linq.ForeignKeyReferenceAlreadyHasValueException();
                    }
                    this.OnrefFacultyChanging(value);
                    this.SendPropertyChanging();
                    this._refFaculty = value;
                    this.SendPropertyChanged("refFaculty");
                    this.OnrefFacultyChanged();
                }
            }
        }

        [ColumnAttribute(Storage = "_refSchool", DbType = "SmallInt")]
        public Nullable<short> refSchool
        {
            get
            {
                return this._refSchool;
            }
            set
            {
                if ((this._refSchool != value))
                {
                    if (this._School.HasLoadedOrAssignedValue)
                    {
                        throw new System.Data.Linq.ForeignKeyReferenceAlreadyHasValueException();
                    }
                    this.OnrefSchoolChanging(value);
                    this.SendPropertyChanging();
                    this._refSchool = value;
                    this.SendPropertyChanged("refSchool");
                    this.OnrefSchoolChanged();
                }
            }
        }

        [ColumnAttribute(Storage = "_refAddress", DbType = "SmallInt")]
        public Nullable<short> refAddress
        {
            get
            {
                return this._refAddress;
            }
            set
            {
                if ((this._refAddress != value))
                {
                    if (this._Address.HasLoadedOrAssignedValue)
                    {
                        throw new System.Data.Linq.ForeignKeyReferenceAlreadyHasValueException();
                    }
                    this.OnrefAddressChanging(value);
                    this.SendPropertyChanging();
                    this._refAddress = value;
                    this.SendPropertyChanged("refAddress");
                    this.OnrefAddressChanged();
                }
            }
        }

        [ColumnAttribute(Storage = "_familyName", DbType = "VarChar(75) NOT NULL", CanBeNull = false)]
        public string familyName
        {
            get
            {
                return this._familyName;
            }
            set
            {
                if ((this._familyName != value))
                {
                    this.OnfamilyNameChanging(value);
                    this.SendPropertyChanging();
                    this._familyName = value;
                    this.SendPropertyChanged("familyName");
                    this.OnfamilyNameChanged();
                }
            }
        }

        [ColumnAttribute(Storage = "_studentName", DbType = "VarChar(75) NOT NULL", CanBeNull = false)]
        public string studentName
        {
            get
            {
                return this._studentName;
            }
            set
            {
                if ((this._studentName != value))
                {
                    this.OnstudentNameChanging(value);
                    this.SendPropertyChanging();
                    this._studentName = value;
                    this.SendPropertyChanged("studentName");
                    this.OnstudentNameChanged();
                }
            }
        }

        [ColumnAttribute(Storage = "_fatherName", DbType = "VarChar(75)")]
        public string fatherName
        {
            get
            {
                return this._fatherName;
            }
            set
            {
                if ((this._fatherName != value))
                {
                    this.OnfatherNameChanging(value);
                    this.SendPropertyChanging();
                    this._fatherName = value;
                    this.SendPropertyChanged("fatherName");
                    this.OnfatherNameChanged();
                }
            }
        }

        [ColumnAttribute(Storage = "_bornDate", DbType = "DateTime")]
        public Nullable<DateTime> bornDate
        {
            get
            {
                return this._bornDate;
            }
            set
            {
                if ((this._bornDate != value))
                {
                    this.OnbornDateChanging(value);
                    this.SendPropertyChanging();
                    this._bornDate = value;
                    this.SendPropertyChanged("bornDate");
                    this.OnbornDateChanged();
                }
            }
        }

        [ColumnAttribute(Storage = "_email", DbType = "VarChar(100)")]
        public string email
        {
            get
            {
                return this._email;
            }
            set
            {
                if ((this._email != value))
                {
                    this.OnemailChanging(value);
                    this.SendPropertyChanging();
                    this._email = value;
                    this.SendPropertyChanged("email");
                    this.OnemailChanged();
                }
            }
        }

        [ColumnAttribute(Storage = "_homePhone", DbType = "VarChar(25)")]
        public string homePhone
        {
            get
            {
                return this._homePhone;
            }
            set
            {
                if ((this._homePhone != value))
                {
                    this.OnhomePhoneChanging(value);
                    this.SendPropertyChanging();
                    this._homePhone = value;
                    this.SendPropertyChanged("homePhone");
                    this.OnhomePhoneChanged();
                }
            }
        }

        [ColumnAttribute(Storage = "_mobilePhone", DbType = "VarChar(25)")]
        public string mobilePhone
        {
            get
            {
                return this._mobilePhone;
            }
            set
            {
                if ((this._mobilePhone != value))
                {
                    this.OnmobilePhoneChanging(value);
                    this.SendPropertyChanging();
                    this._mobilePhone = value;
                    this.SendPropertyChanged("mobilePhone");
                    this.OnmobilePhoneChanged();
                }
            }
        }

        [ColumnAttribute(Storage = "_additionalPhone", DbType = "VarChar(25)")]
        public string additionalPhone
        {
            get
            {
                return this._additionalPhone;
            }
            set
            {
                if ((this._additionalPhone != value))
                {
                    this.OnadditionalPhoneChanging(value);
                    this.SendPropertyChanging();
                    this._additionalPhone = value;
                    this.SendPropertyChanged("additionalPhone");
                    this.OnadditionalPhoneChanged();
                }
            }
        }

        [ColumnAttribute(Storage = "_isPrivilege", DbType = "Bit")]
        public bool isPrivilege
        {
            get
            {
                return this._isPrivilege;
            }
            set
            {
                if ((this._isPrivilege != value))
                {
                    this.OnisPrivilegeChanging(value);
                    this.SendPropertyChanging();
                    this._isPrivilege = value;
                    this.SendPropertyChanged("isPrivilege");
                    this.OnisPrivilegeChanged();
                }
            }
        }

        [AssociationAttribute(Name = "Student_Payment", Storage = "_Payments", ThisKey = "idStudent", OtherKey = "refStudent")]
        public EntitySet<Payment> Payments
        {
            get
            {
                return this._Payments;
            }
            set
            {
                this._Payments.Assign(value);
            }
        }

        [AssociationAttribute(Name = "Student_StudentGroup", Storage = "_StudentGroups", ThisKey = "idStudent", OtherKey = "refStudent")]
        public EntitySet<StudentGroup> StudentGroups
        {
            get
            {
                return this._StudentGroups;
            }
            set
            {
                this._StudentGroups.Assign(value);
            }
        }

        [AssociationAttribute(Name = "Address_Student", Storage = "_Address", ThisKey = "refAddress", OtherKey = "idAddress", IsForeignKey = true)]
        public Address Address
        {
            get
            {
                return this._Address.Entity;
            }
            set
            {
                Address previousValue = this._Address.Entity;
                if (((previousValue != value)
                     || (this._Address.HasLoadedOrAssignedValue == false)))
                {
                    this.SendPropertyChanging();
                    if ((previousValue != null))
                    {
                        this._Address.Entity = null;
                        previousValue.Students.Remove(this);
                    }
                    this._Address.Entity = value;
                    if ((value != null))
                    {
                        value.Students.Add(this);
                        this._refAddress = value.idAddress;
                    }
                    else
                    {
                        this._refAddress = default(Nullable<short>);
                    }
                    this.SendPropertyChanged("Address");
                }
            }
        }

        [AssociationAttribute(Name = "Faculty_Student", Storage = "_Faculty", ThisKey = "refFaculty", OtherKey = "idFaculty", IsForeignKey = true)]
        public Faculty Faculty
        {
            get
            {
                return this._Faculty.Entity;
            }
            set
            {
                Faculty previousValue = this._Faculty.Entity;
                if (((previousValue != value)
                     || (this._Faculty.HasLoadedOrAssignedValue == false)))
                {
                    this.SendPropertyChanging();
                    if ((previousValue != null))
                    {
                        this._Faculty.Entity = null;
                        previousValue.Students.Remove(this);
                    }
                    this._Faculty.Entity = value;
                    if ((value != null))
                    {
                        value.Students.Add(this);
                        this._refFaculty = value.idFaculty;
                    }
                    else
                    {
                        this._refFaculty = default(Nullable<short>);
                    }
                    this.SendPropertyChanged("Faculty");
                }
            }
        }

        [AssociationAttribute(Name = "School_Student", Storage = "_School", ThisKey = "refSchool", OtherKey = "idSchool", IsForeignKey = true)]
        public School School
        {
            get
            {
                return _School.Entity;
            }
            set
            {
                var previousValue = _School.Entity;
                if (((previousValue != value)
                     || (_School.HasLoadedOrAssignedValue == false)))
                {
                    SendPropertyChanging();
                    if ((previousValue != null))
                    {
                        _School.Entity = null;
                        previousValue.Students.Remove(this);
                    }
                    _School.Entity = value;
                    if ((value != null))
                    {
                        value.Students.Add(this);
                        _refSchool = value.idSchool;
                    }
                    else
                    {
                        _refSchool = default(Nullable<short>);
                    }
                    SendPropertyChanged("School");
                }
            }
        }

        public event PropertyChangingEventHandler PropertyChanging;

        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void SendPropertyChanging()
        {
            if ((PropertyChanging != null))
            {
                PropertyChanging(this, emptyChangingEventArgs);
            }
        }

        protected virtual void SendPropertyChanged(String propertyName)
        {
            if ((PropertyChanged != null))
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        private void AttachPayments(Payment entity)
        {
            SendPropertyChanging();
            entity.Student = this;
        }

        private void DetachPayments(Payment entity)
        {
            SendPropertyChanging();
            entity.Student = null;
        }

        private void AttachStudentGroups(StudentGroup entity)
        {
            SendPropertyChanging();
            entity.Student = this;
        }

        private void DetachStudentGroups(StudentGroup entity)
        {
            SendPropertyChanging();
            entity.Student = null;
        }

        public override Model.ModelClasses.AbstractModel PureModel
        {
            get
            { return base.PureModel; }
            set
            {
                if(PureModel != null)
                {
                    //  Прекращаем прослушивание оповещений от текущего объекта модели
                    _pureModel.UpdateModelEvent -= UpdateModelEventHandler;
                    if (((IStudent)_pureModel).Groups != null)
                    {
                        ((IStudent)_pureModel).Groups.AddedItemEvent -= AddedGroupEventHandler;
                        ((IStudent)_pureModel).Groups.RemovedItemEvent -= RemovedGroupEventHandler;
                    }
                    if(((IStudent)_pureModel).Payments != null)
                    {
                        ((IStudent)_pureModel).Payments.AddedItemEvent -= AddedPaymentEventHandler;
                        ((IStudent)_pureModel).Payments.RemovedItemEvent -= RemovedPaymentEventHandler;
                    }
                }
                if(value != null)
                {
                    //  Подписываемся на оповещение нового объекта модели
                    value.UpdateModelEvent += UpdateModelEventHandler;
                    if (((IStudent)value).Groups != null)
                    {
                        ((IStudent)value).Groups.AddedItemEvent += AddedGroupEventHandler;
                        ((IStudent)value).Groups.RemovedItemEvent += RemovedGroupEventHandler;
                    }
                    if (((IStudent)value).Payments != null)
                    {
                        ((IStudent)value).Payments.AddedItemEvent += AddedPaymentEventHandler;
                        ((IStudent)value).Payments.RemovedItemEvent += RemovedPaymentEventHandler;
                    }
                }
                _pureModel = value;
            }
        }

        private void RemovedPaymentEventHandler(object sender, ModelItemEventArgs e)
        {
            if (RemovedPaymentEvent != null)
                RemovedPaymentEvent(this, e);
        }

        private void AddedPaymentEventHandler(object sender, ModelItemEventArgs e)
        {
            if (AddedPaymentEvent != null)
                AddedPaymentEvent(this, e);
        }

        private void RemovedGroupEventHandler(object sender, ModelItemEventArgs e)
        {
            if(RemovedGroupEvent != null)
                RemovedGroupEvent(this, e);
        }

        private void AddedGroupEventHandler(object sender, ModelItemEventArgs e)
        {
            if (AddedGroupEvent != null)
                AddedGroupEvent(this, e);
        }

        private void UpdateModelEventHandler(object sender, EventArgs e)
        {
            var pureModel = ((IStudent) _pureModel);
            //  <update simple fields>
            familyName = pureModel.FamilyName;
            studentName = pureModel.Name;
            fatherName = pureModel.FatherName;
            bornDate = pureModel.Birthday;
            isPrivilege = pureModel.IsBenefit;
            homePhone = pureModel.ContactInformation.LandlinePhone;
            mobilePhone = pureModel.ContactInformation.MobilePhone;
            additionalPhone = pureModel.ContactInformation.AdditionalPhone;
            email = pureModel.ContactInformation.Email;
            //  </update simple fields>

            //  обновление оплат, адреса, факультета, школы делегируется в DataDispatcher,
            //  так как он обладает необходимыми для этого полномочиями (получать данные из разных таблиц)
            UpdateData();   //  оповещаем DataDispatcher о том, что простые поля уже обновлены и теперь нужно обновить "сложные" поля
        }
    }
}